// 版权所有2009 Go作者。保留所有权利。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

// 该文件实现了对信号处理的运行时支持。

package runtime

import _ "unsafe"

const qsize = 64

var sig struct {
	q     noteQueue
	inuse bool

	lock     mutex
	note     note
	sleeping bool
}

type noteData struct {
	s [_ERRMAX]byte
	n int // n字节的s是有效的
}

type noteQueue struct {
	lock mutex
	data [qsize]noteData
	ri   int
	wi   int
	full bool
}

// 不允许在信号处理程序中分配内存。
func (q *noteQueue) push(item *byte) bool {
	lock(&q.lock)
	if q.full {
		unlock(&q.lock)
		return false
	}
	s := gostringnocopy(item)
	copy(q.data[q.wi].s[:], s)
	q.data[q.wi].n = len(s)
	q.wi++
	if q.wi == qsize {
		q.wi = 0
	}
	if q.wi == q.ri {
		q.full = true
	}
	unlock(&q.lock)
	return true
}

func (q *noteQueue) pop() string {
	lock(&q.lock)
	q.full = false
	if q.ri == q.wi {
		unlock(&q.lock)
		return ""
	}
	note := &q.data[q.ri]
	item := string(note.s[:note.n])
	q.ri++
	if q.ri == qsize {
		q.ri = 0
	}
	unlock(&q.lock)
	return item
}

// 从sighandler调用，将信号发送回信号处理线程。
// 报告信号是否已发送。否则，调用方通常会使程序崩溃。
func sendNote(s *byte) bool {
	if !sig.inuse {
		return false
	}

	// 向传出队列添加信号。
	if !sig.q.push(s) {
		return false
	}

	lock(&sig.lock)
	if sig.sleeping {
		sig.sleeping = false
		notewakeup(&sig.note)
	}
	unlock(&sig.lock)

	return true
}

// 调用以接收下一个排队信号。
// 一次只能从一个goroutine调用。
// go:linkname信号\接收操作系统/信号。signal_recv 
func signal_recv() string {
	for {
		note := sig.q.pop()
		if note != "" {
			return note
		}

		lock(&sig.lock)
		sig.sleeping = true
		noteclear(&sig.note)
		unlock(&sig.lock)
		notetsleepg(&sig.note, -1)
	}
}

// signalwaituntille等待信号传递机制空闲。
// 这用于确保我们不会因为
// 禁用信号和接收信号之间的竞争而放弃信号通知。
// 这假设
// 相关信号的信号传输已被禁用，我们只是在等待确认
// 所有信号已通过os/信号包传输到用户通道
// 上。
// go:linkname signal waituntille os/signal。SignalWaitUntillidle 
func signalWaitUntilIdle() {
	for {
		lock(&sig.lock)
		sleeping := sig.sleeping
		unlock(&sig.lock)
		if sleeping {
			return
		}
		Gosched()
	}
}

// 一次只能从一个goroutine调用。
// go:linkname信号\启用操作系统/信号。signal_enable 
func signal_enable(s uint32) {
	if !sig.inuse {
		// 这是第一次调用signal_enable。初始化。
		sig.inuse = true // 启用信号接收；无法禁用
		noteclear(&sig.note)
	}
}

// 一次只能从一个goroutine调用。
// go:linkname信号\禁用操作系统/信号。信号_disable 
func signal_disable(s uint32) {
}

// 一次只能从一个goroutine调用。
// go:linkname信号\u忽略操作系统/信号。signal_ignore 
func signal_ignore(s uint32) {
}

// go:linkname signal_ignored os/signal。信号被忽略
func signal_ignored(s uint32) bool {
	return false
}
